home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1993
/
Internet Info CD-ROM (Walnut Creek) (1993).iso
/
networking
/
cisco
/
tcpf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-07
|
12KB
|
419 lines
/*
* tcpf.c -- TCP to stdio filter
*
* July 1987, Kirk Lougheed
*
* Copyright (c) 1987 by cisco Systems, Inc.
*
* This program is designed to read and write from standard input and
* output to a raw TCP socket. The specific application is sending data
* to printers attached to a terminal server's serial or parallel ports.
*
* This program may be used in a shell script. The following example is
* of a "print" command that sends text to a PostScript printer.
*
* /usr/local/bin/lptops -2 -o -ntr $* | /usr/local/bin/tcpf -e chaff 4008 &
*
* To use it to stuff a file at a gateway called wilma, for instance, use
* the command line:
*
* tcpf -t wilma 23 <doit
*
* where the file doit contains, for instance:
*
* foo^M
* ena
* foobar^M
* ping
* ip^Mnit^M100^M^M^M^M
* disa
* exit
*
* This script will log onto wilma, get into enable mode, then send 100 pings
* aimed at nit. Output from wilma will be delivered back to the initiator.
*
* Note that the ^M's in this message must be actual control-M's in the
* file -- most of the parsing uses 015 as the line terminator, and tcpf
* does not deal with NVT or CRLF issues. It turns out that our exec
* uses 015 or 012 as a line terminator, so the some of the commands can
* have normal newlines at the end.
*/
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <errno.h>
#define TRUE 1
#define FALSE 0
#define LF 0xA
#define CR 0xD
/* Accommodate worst case for stupid printers (-r switch) */
#define TCPFBUFSIZ (BUFSIZ * 2)
int debug; /* -d switch */
int eofmode; /* -e switch */
int timeoutmode; /* -t switch */
int crlfmode; /* -r switch */
int timeoutlen;
int openwait; /* -w switch */
int openwaitlen;
struct sockaddr_in sock;
jmp_buf terminate;
unsigned char netbuffer[BUFSIZ];
unsigned char netoutbuffer[TCPFBUFSIZ];
unsigned char ttybuffer[BUFSIZ];
int bytesread, byteswrote;
void crashed();
void transfer();
/*
* main
* Parse command line and set up transfer.
*
* tcpf [-d -e -r -t -w] host port
*
* -d Enable debugging output.
* -e Send CTRL/D over TCP side when EOF received on stdin.
* This makes PostScript printers very happy.
* -r Send a <CR><LF> pair to stream for every <LF> given
* in stdin.
* -t[time] Timeout in seconds. Default is 5 min.
* -w[time] Wait for Time while opening connection too.
* host Host name, either symbolic or dotted decimal.
* port Decimal TCP port number. No defaults.
*/
main(argc, argv)
int argc;
char *argv[];
{
char *hostname;
unsigned short port;
int conn;
debug = FALSE;
eofmode = FALSE;
timeoutmode = FALSE;
crlfmode = FALSE;
argc--; argv++;
while (argc > 1 && (argv[0][0] == '-')) {
switch (argv[0][1]) {
case 'd':
case 'D':
debug = TRUE;
break;
case 'e':
case 'E':
eofmode = TRUE;
break;
case 'r':
case 'R':
crlfmode = TRUE;
break;
case 't':
case 'T':
timeoutmode = TRUE;
timeoutlen = atoi(&argv[0][2]);
if (timeoutlen == 0)
timeoutlen = 300;
break;
case 'w':
case 'W':
openwait = TRUE;
openwaitlen = atoi(&argv[0][2]);
if (openwaitlen <= 0)
openwaitlen = 300;
break;
default:
fprintf(stderr, "Usage: tcpf [-d -e -r -t[sec] -w[sec]] host port\n");
exit(1);
}
argc--; argv++;
}
if (argc != 2) {
fprintf(stderr, "Usage: tcpf [-d -e -t[sec] -w[sec]] host port\n");
exit(1);
}
hostname = argv[0];
port = atoi(argv[1]);
if (!setup_socket(&sock, hostname, port))
exit(1);
if (debug) {
fprintf(stderr, "Connecting to \"%s, %d\"... ",
inet_ntoa(sock.sin_addr), ntohs(sock.sin_port));
fflush(stderr);
}
conn = setup_connection(&sock);
if (conn < 0)
exit(1);
signal(SIGPIPE, crashed);
if (setjmp(terminate) == 0)
transfer(conn);
close(conn);
if (debug)
fprintf(stderr, "\nNet connection closed: %d bytes written, %d read\n",
byteswrote, bytesread);
exit(0);
}
/*
* setup_socket
* Turn a hostname string and port into a sockaddr structure.
* Returns TRUE or FALSE.
*/
int
setup_socket(soc, host, port)
struct sockaddr_in *soc;
char *host;
unsigned short port;
{
struct hostent *entry;
soc->sin_family = AF_INET;
soc->sin_port = htons(port);
soc->sin_addr.s_addr = inet_addr(host);
if (soc->sin_addr.s_addr != -1)
return(TRUE);
entry = gethostbyname(host);
if (entry && entry->h_addr && (entry->h_addrtype == AF_INET)) {
bcopy(entry->h_addr,&soc->sin_addr.s_addr, entry->h_length);
/* strncpy(&soc->sin_addr.s_addr, entry->h_addr, entry->h_length); */
return(TRUE);
}
fprintf(stderr, "Unknown hostname or address - \"%s\"\n", host);
return(FALSE);
}
/*
* crashed
* Come here if connection failed
*/
void
crashed()
{
if (debug)
perror("tcpf lost connection");
longjmp(terminate, 1);
}
/*
* setup_connection
* Open a TCP connection to the specified address
*/
int
setup_connection(soc)
struct sockaddr_in *soc;
{
int conn;
int i;
conn = socket(AF_INET, SOCK_STREAM, 0);
if (conn < 0) {
if (debug)
perror("socket");
return(-1);
}
if (openwait) {
for (i=0; i < openwaitlen; i++) {
if (connect(conn,soc, sizeof(*soc)) >= 0)
break;
if (i==0 && debug) {
fprintf(stderr,"Waiting... ");
fflush(stderr);
}
sleep(1);
close(conn);
conn = socket(AF_INET, SOCK_STREAM, 0);
if (conn < 0) {
if (debug)
perror("socket");
return(-1);
}
}
if (i >= openwaitlen) {
if (debug)
perror("connect");
return(-1);
}
} else if (connect(conn, soc, sizeof(*soc)) < 0) {
if (debug)
perror("connect");
return(-1);
}
if (debug)
fprintf(stderr, "Open\n");
return(conn);
}
/*
* transfer
* Write data from stdin to the specified connection.
* Read data from connection to stdout.
*/
void
transfer(net)
int net;
{
int tib, nib, count;
unsigned char *tibptr, *nibptr, *stiptr, *stoptr;
int nready, readmask, writemask;
int stdinmask, stdoutmask, netinmask, netoutmask;
struct timeval timeout;
int neteof, stdeof, nonblock;
bytesread = byteswrote = 0;
tib = nib = 0;
neteof = stdeof = FALSE;
stdinmask = (1 << fileno(stdin));
stdoutmask = (1 << fileno(stdout));
netinmask = (1 << net);
netoutmask = (1 << net);
timeout.tv_sec = timeoutlen;
timeout.tv_usec = 0;
nonblock = 1;
ioctl(net, FIONBIO, &nonblock);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
while (TRUE) {
if ((tib == 0) && (nib == 0) && (neteof == TRUE) && (stdeof == TRUE))
return;
readmask = 0;
if (tib == 0)
readmask |= (stdeof ? 0 : stdinmask);
if (nib == 0)
readmask |= (neteof ? 0 : netinmask);
writemask = 0;
if (tib)
writemask |= netoutmask;
if (nib)
writemask |= stdoutmask;
nready = select(8*sizeof(int), &readmask, &writemask, NULL,
(timeoutmode ? &timeout : NULL));
if (debug)
printf("\nnready %d, rmask %4x, wmask %4x",
nready, readmask, writemask);
if (nready <= 0)
/* exit if timeout or eror */
return;
/*
* First we try reading from the net
*/
if ((nib == 0) && (readmask & netinmask) && (neteof == FALSE)) {
nibptr = netbuffer;
nib = read(net, nibptr, BUFSIZ);
if (debug)
fprintf(stderr,"\nRead %d bytes from net", nib);
if ((nib == 0) || (nib == -1)) {
nib = 0;
neteof = TRUE;
}
else {
bytesread += nib;
if (eofmode && (netbuffer[nib-1] == '\004')) {
netbuffer[--nib] = '\000';
neteof = TRUE;
}
}
}
/*
* If we have input from the net, try writing it to standard out.
*/
if ((nib > 0) && (writemask & stdoutmask)) {
count = write(fileno(stdout), nibptr, nib);
if (debug)
fprintf(stderr,"\nWrote %d bytes to stdout", count);
if ((count == nib) || (count < 0))
nib = 0;
else {
nibptr += count;
nib -= count;
}
}
/*
* Now read from standard input. If we read EOF and the user
* wants us to pass it through, send a CTRL/D. This is very
* useful when dealing with PostScript printers that require
* the last character of a job be CTRL/D.
*/
if ((tib == 0) && (readmask & stdinmask) && (stdeof == FALSE)) {
tibptr = ttybuffer;
tib = read(fileno(stdin), tibptr, BUFSIZ);
if (debug)
fprintf(stderr,"\nRead %d bytes from stdin", tib);
if ((tib == 0) || (tib == -1)) {
if ((tib == 0) && (eofmode == TRUE) && byteswrote) {
if (debug)
fprintf(stderr, " -- sending EOF character");
tib = 1;
ttybuffer[0] = '\004';
}
else
tib = 0;
stdeof = TRUE;
}
/*
* Convert <LF> to <CR><LF>. Preexisting <CR><LF> pairs not hurt,
* as <CR><CR><LF> has same effect. Uses this slow loop, rather
* than "memccpy", because the memory routines do not exist on
* all Unixes.
*/
if (crlfmode) {
for (stiptr = ttybuffer, stoptr = netoutbuffer;
((stiptr - ttybuffer) < tib);) {
if (*stiptr == LF) {
*stoptr++ = CR;
}
*stoptr++ = *stiptr++;
}
tib = (stoptr - netoutbuffer);
tibptr = netoutbuffer;
}
}
/*
* If we have input from standard input, try writing to the net
*/
if ((tib > 0) && (writemask & netoutmask)) {
errno = 0;
count = write(net, tibptr, tib);
if (debug)
fprintf(stderr,"\nWrote %d bytes to net", count);
if (count < 0) {
if ((errno != ENOBUFS) && (errno != EWOULDBLOCK))
longjmp(terminate, -1);
count = 0;
}
byteswrote += count;
tibptr += count;
tib -= count;
}
/*
* If we hit EOF on either side, maybe set EOF on other side.
*/
if ((stdeof == TRUE) && ((readmask & netinmask) == 0)&&(!timeoutmode))
neteof = TRUE;
if ((neteof == TRUE) && ((readmask & stdinmask) == 0)&&(!timeoutmode))
stdeof = TRUE;
}
}